

#import "textReader.h"

#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <ctype.h>
#include "rtftype.h"
#include "rtfdecl.h"

// RTF parser tables

// Property descriptions
static PROP rgprop[ipropMax] = {
    {actnByte,   propChp,    offsetof(CHP, fBold)},       // ipropBold
    {actnByte,   propChp,    offsetof(CHP, fItalic)},     // ipropItalic
    {actnByte,   propChp,    offsetof(CHP, fUnderline)},  // ipropUnderline
    {actnWord,   propPap,    offsetof(PAP, xaLeft)},      // ipropLeftInd
    {actnWord,   propPap,    offsetof(PAP, xaRight)},     // ipropRightInd
    {actnWord,   propPap,    offsetof(PAP, xaFirst)},     // ipropFirstInd
    {actnWord,   propSep,    offsetof(SEP, cCols)},       // ipropCols
    {actnWord,   propSep,    offsetof(SEP, xaPgn)},       // ipropPgnX
    {actnWord,   propSep,    offsetof(SEP, yaPgn)},       // ipropPgnY
    {actnWord,   propDop,    offsetof(DOP, xaPage)},      // ipropXaPage
    {actnWord,   propDop,    offsetof(DOP, yaPage)},      // ipropYaPage
    {actnWord,   propDop,    offsetof(DOP, xaLeft)},      // ipropXaLeft
    {actnWord,   propDop,    offsetof(DOP, xaRight)},     // ipropXaRight
    {actnWord,   propDop,    offsetof(DOP, yaTop)},       // ipropYaTop
    {actnWord,   propDop,    offsetof(DOP, yaBottom)},    // ipropYaBottom
    {actnWord,   propDop,    offsetof(DOP, pgnStart)},    // ipropPgnStart
    {actnByte,   propSep,    offsetof(SEP, sbk)},         // ipropSbk
    {actnByte,   propSep,    offsetof(SEP, pgnFormat)},   // ipropPgnFormat
    {actnByte,   propDop,    offsetof(DOP, fFacingp)},    // ipropFacingp
    {actnByte,   propDop,    offsetof(DOP, fLandscape)},  // ipropLandscape
    {actnByte,   propPap,    offsetof(PAP, just)},        // ipropJust
    {actnSpec,   propPap,    0},                          // ipropPard
    {actnSpec,   propChp,    0},                          // ipropPlain
    {actnSpec,   propSep,    0},                          // ipropSectd
};

// Keyword descriptions
static SYM rgsymRtf[] = {
//  keyword     dflt    fPassDflt   kwd         idx
    {"b",        1,      fFalse,     kwdProp,    ipropBold},
    {"u",        1,      fFalse,     kwdProp,    ipropUnderline},
    {"i",        1,      fFalse,     kwdProp,    ipropItalic},
    {"li",       0,      fFalse,     kwdProp,    ipropLeftInd},
    {"ri",       0,      fFalse,     kwdProp,    ipropRightInd},
    {"fi",       0,      fFalse,     kwdProp,    ipropFirstInd},
    {"cols",     1,      fFalse,     kwdProp,    ipropCols},
    {"sbknone",  sbkNon, fTrue,      kwdProp,    ipropSbk},
    {"sbkcol",   sbkCol, fTrue,      kwdProp,    ipropSbk},
    {"sbkeven",  sbkEvn, fTrue,      kwdProp,    ipropSbk},
    {"sbkodd",   sbkOdd, fTrue,      kwdProp,    ipropSbk},
    {"sbkpage",  sbkPg,  fTrue,      kwdProp,    ipropSbk},
    {"pgnx",     0,      fFalse,     kwdProp,    ipropPgnX},
    {"pgny",     0,      fFalse,     kwdProp,    ipropPgnY},
    {"pgndec",   pgDec,  fTrue,      kwdProp,    ipropPgnFormat},
    {"pgnucrm",  pgURom, fTrue,      kwdProp,    ipropPgnFormat},
    {"pgnlcrm",  pgLRom, fTrue,      kwdProp,    ipropPgnFormat},
    {"pgnucltr", pgULtr, fTrue,      kwdProp,    ipropPgnFormat},
    {"pgnlcltr", pgLLtr, fTrue,      kwdProp,    ipropPgnFormat},
    {"qc",       justC,  fTrue,      kwdProp,    ipropJust},
    {"ql",       justL,  fTrue,      kwdProp,    ipropJust},
    {"qr",       justR,  fTrue,      kwdProp,    ipropJust},
    {"qj",       justF,  fTrue,      kwdProp,    ipropJust},
    {"paperw",   12240,  fFalse,     kwdProp,    ipropXaPage},
    {"paperh",   15480,  fFalse,     kwdProp,    ipropYaPage},
    {"margl",    1800,   fFalse,     kwdProp,    ipropXaLeft},
    {"margr",    1800,   fFalse,     kwdProp,    ipropXaRight},
    {"margt",    1440,   fFalse,     kwdProp,    ipropYaTop},
    {"margb",    1440,   fFalse,     kwdProp,    ipropYaBottom},
    {"pgnstart", 1,      fTrue,      kwdProp,    ipropPgnStart},
    {"facingp",  1,      fTrue,      kwdProp,    ipropFacingp},
    {"landscape",1,      fTrue,      kwdProp,    ipropLandscape},
    {"par",      0,      fFalse,     kwdChar,    0x0a},
    
    
    
    // JIMB BUG BUG ...
    // Most of these need better mapping ...
    {"emspace",  0,      fFalse,     kwdChar,    ' '},
    {"enspace",  0,      fFalse,     kwdChar,    ' '},
    {"~",        0,      fFalse,     kwdChar,    ' '},
    {"lquote",   0,      fFalse,     kwdChar,    '\''},
    {"rquote",   0,      fFalse,     kwdChar,    '\''},
    {"-",        0,      fFalse,     kwdChar,    '-'},
    {"_",        0,      fFalse,     kwdChar,    '-'},
    {"emdash",   0,      fFalse,     kwdChar,    '-'},
    {"endash",   0,      fFalse,     kwdChar,    '-'},
    {"line",     0,      fFalse,     kwdChar,    0x0a},
    {"page",     0,      fFalse,     kwdChar,    0x0a},
    {"pagebb",   0,      fFalse,     kwdChar,    0x0a},
    {"outlinelevel",  0, fFalse,     kwdChar,    0x0a},


    
    {"\0x0a",    0,      fFalse,     kwdChar,    0x0a},
    {"\0x0d",    0,      fFalse,     kwdChar,    0x0a},
    {"tab",      0,      fFalse,     kwdChar,    0x09},
    {"ldblquote",0,      fFalse,     kwdChar,    '"'},
    {"rdblquote",0,      fFalse,     kwdChar,    '"'},
    {"bin",      0,      fFalse,     kwdSpec,    ipfnBin},
    {"*",        0,      fFalse,     kwdSpec,    ipfnSkipDest},
    {"'",        0,      fFalse,     kwdSpec,    ipfnHex},
    {"author",   0,      fFalse,     kwdDest,    idestSkip},
    {"buptim",   0,      fFalse,     kwdDest,    idestSkip},
    {"colortbl", 0,      fFalse,     kwdDest,    idestSkip},
    {"comment",  0,      fFalse,     kwdDest,    idestSkip},
    {"creatim",  0,      fFalse,     kwdDest,    idestSkip},
    {"doccomm",  0,      fFalse,     kwdDest,    idestSkip},
    {"fonttbl",  0,      fFalse,     kwdDest,    idestSkip},
    {"footer",   0,      fFalse,     kwdDest,    idestSkip},
    {"footerf",  0,      fFalse,     kwdDest,    idestSkip},
    {"footerl",  0,      fFalse,     kwdDest,    idestSkip},
    {"footerr",  0,      fFalse,     kwdDest,    idestSkip},
    {"footnote", 0,      fFalse,     kwdDest,    idestSkip},
    {"ftncn",    0,      fFalse,     kwdDest,    idestSkip},
    {"ftnsep",   0,      fFalse,     kwdDest,    idestSkip},
    {"ftnsepc",  0,      fFalse,     kwdDest,    idestSkip},
    {"header",   0,      fFalse,     kwdDest,    idestSkip},
    {"headerf",  0,      fFalse,     kwdDest,    idestSkip},
    {"headerl",  0,      fFalse,     kwdDest,    idestSkip},
    {"headerr",  0,      fFalse,     kwdDest,    idestSkip},
    {"info",     0,      fFalse,     kwdDest,    idestSkip},
    {"keywords", 0,      fFalse,     kwdDest,    idestSkip},
    {"operator", 0,      fFalse,     kwdDest,    idestSkip},
    {"pict",     0,      fFalse,     kwdDest,    idestSkip},
    {"printim",  0,      fFalse,     kwdDest,    idestSkip},
    {"private1", 0,      fFalse,     kwdDest,    idestSkip},
    {"revtim",   0,      fFalse,     kwdDest,    idestSkip},
    {"rxe",      0,      fFalse,     kwdDest,    idestSkip},
    {"stylesheet",   0,  fFalse,     kwdDest,    idestSkip},
    {"subject",  0,      fFalse,     kwdDest,    idestSkip},
    {"tc",       0,      fFalse,     kwdDest,    idestSkip},
    {"title",    0,      fFalse,     kwdDest,    idestSkip},
    {"txe",      0,      fFalse,     kwdDest,    idestSkip},
    {"xe",       0,      fFalse,     kwdDest,    idestSkip},
    {"{",        0,      fFalse,     kwdChar,    '{'},
    {"}",        0,      fFalse,     kwdChar,    '}'},
    {"\\",       0,      fFalse,     kwdChar,    '\\'}
    };
int isymMax = sizeof(rgsymRtf) / sizeof(SYM);

//
// %%Function: ecApplyPropChange
//
// Set the property identified by _iprop_ to the value _val_.
//
//

int
ecApplyPropChange(IPROP iprop, int val)
{
    char *pb;

    if (rds == rdsSkip)                 // If we're skipping text,
        return ecOK;                    // don't do anything.

    switch (rgprop[iprop].prop)
    {
    case propDop:
        pb = (char *)&dop;
        break;
    case propSep:
        pb = (char *)&sep;
        break;
    case propPap:
        pb = (char *)&pap;
        break;
    case propChp:
        pb = (char *)&chp;
        break;
    default:
        if (rgprop[iprop].actn != actnSpec)
            return ecBadTable;
        break;
    }
    switch (rgprop[iprop].actn)
    {
    case actnByte:
        pb[rgprop[iprop].offset] = (unsigned char) val;
        break;
    case actnWord:
        (*(int *) (pb+rgprop[iprop].offset)) = val;
        break;
    case actnSpec:
        return ecParseSpecialProperty(iprop, val);
        break;
    default:
        return ecBadTable;
    }
    return ecOK;
}

//
// %%Function: ecParseSpecialProperty
//
// Set a property that requires code to evaluate.
//

int
ecParseSpecialProperty(IPROP iprop, int val)
{
    switch (iprop)
    {
    case ipropPard:
        memset(&pap, 0, sizeof(pap));
        return ecOK;
    case ipropPlain:
        memset(&chp, 0, sizeof(chp));
        return ecOK;
    case ipropSectd:
        memset(&sep, 0, sizeof(sep));
        return ecOK;
    default:
        return ecBadTable;
    }
    return ecBadTable;
}

//
// %%Function: ecTranslateKeyword.
//
// Step 3.
// Search rgsymRtf for szKeyword and evaluate it appropriately.
//
// Inputs:
// szKeyword:   The RTF control to evaluate.
// param:       The parameter of the RTF control.
// fParam:      fTrue if the control had a parameter; (that is, if param is valid)
//              fFalse if it did not.
//

int
ecTranslateKeyword(char *szKeyword, int param, bool fParam, RTFDOC * fp)
{
    int isym;

    // search for szKeyword in rgsymRtf

    for (isym = 0; isym < isymMax; isym++)
        if (strcmp(szKeyword, rgsymRtf[isym].szKeyword) == 0)
            break;
    if (isym == isymMax)            // control word not found
    {
        if (fSkipDestIfUnk)         // if this is a new destination
            rds = rdsSkip;          // skip the destination
                                    // else just discard it
        fSkipDestIfUnk = fFalse;
        return ecOK;
    }

    // found it!  use kwd and idx to determine what to do with it.

    fSkipDestIfUnk = fFalse;
    switch (rgsymRtf[isym].kwd)
    {
    case kwdProp:
        if (rgsymRtf[isym].fPassDflt || !fParam)
            param = rgsymRtf[isym].dflt;
        return ecApplyPropChange((IPROP)rgsymRtf[isym].idx, param);
    case kwdChar:
        return ecParseChar(rgsymRtf[isym].idx, fp);
    case kwdDest:
        return ecChangeDest((IDEST)rgsymRtf[isym].idx);
    case kwdSpec:
        return ecParseSpecialKeyword((IPFN)rgsymRtf[isym].idx);
    default:
        return ecBadTable;
    }
    return ecBadTable;
}

//
// %%Function: ecChangeDest
//
// Change to the destination specified by idest.
// There's usually more to do here than this...
//

int
ecChangeDest(IDEST idest)
{
    if (rds == rdsSkip)             // if we're skipping text,
        return ecOK;                // don't do anything

    switch (idest)
    {
    case 0:                         // shut up compiler whine
    default:
        rds = rdsSkip;              // when in doubt, skip it...
        break;
    }
    return ecOK;
}

//
// %%Function: ecEndGroupAction
//
// The destination specified by rds is coming to a close.
// If there's any cleanup that needs to be done, do it now.
//

int
ecEndGroupAction(RDS rds)
{
    return ecOK;
}

//
// %%Function: ecParseSpecialKeyword
//
// Evaluate an RTF control that needs special processing.
//

int
ecParseSpecialKeyword(IPFN ipfn)
{
    if (rds == rdsSkip && ipfn != ipfnBin)  // if we're skipping, and it's not
        return ecOK;                        // the \bin keyword, ignore it.
    switch (ipfn)
    {
    case ipfnBin:
        ris = risBin;
        cbBin = lParam;
        break;
    case ipfnSkipDest:
        fSkipDestIfUnk = fTrue;
        break;
    case ipfnHex:
        ris = risHex;
        break;
    default:
        return ecBadTable;
    }
    return ecOK;
}


